package dj.engine.app;

import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.Stack;

import dj.engine.screen.Screen;
import dj.engine.util.Vec2i;

public abstract class Application extends SwingFrontEnd {

	protected Stack<Screen> currentScreens;
	protected Vec2i size;
	protected Application(String name, boolean fullscreen) {
		super(name, fullscreen);
		// TODO Auto-generated constructor stub
		currentScreens = new Stack<Screen>();
	}
	
	/**
	 * Called at a regular interval set by {@link #setTickFrequency(long)}. Use to update any state
	 * that changes over time.
	 * 
	 * @param nanosSincePreviousTick	approximate number of nanoseconds since the previous call
	 *                              	to onTick
	 */
	public void onTick(long nanosSincePreviousTick)
	{
		currentScreens.peek().onTick(nanosSincePreviousTick);
	}

	/**
	 * Called when the screen needs to be redrawn. This is at least once per tick, but possibly
	 * more frequently (for example, when the window is resizing).
	 * <br><br>
	 * Note that the entire drawing area is cleared before each call to this method. Furthermore,
	 * {@link #onResize} is guaranteed to be called before the first invocation of onDraw.
	 * 
	 * @param g		a {@link Graphics2D} object used for drawing.
	 */
	public void onDraw(Graphics2D g)
	{
		Stack<Screen> toDraw = new Stack<Screen>();
		while(!currentScreens.isEmpty()&&currentScreens.peek().isTransparent())
		{
			toDraw.push(currentScreens.pop());
		}
		if(!currentScreens.isEmpty())
		{
			currentScreens.peek().onDraw(g);
		}
		while(!toDraw.isEmpty())
		{
			Screen drawing = toDraw.pop();
			drawing.onDraw(g);
			currentScreens.push(drawing);
		}
	}

	/**
	 * @param e		an AWT {@link KeyEvent} representing the input event.
	 * @see KeyListener#keyTyped(KeyEvent)
	 */
	public void onKeyTyped(KeyEvent e)
	{
		currentScreens.peek().onKeyTyped(e);
	}

	/**
	 * @param e		an AWT {@link KeyEvent} representing the input event.
	 * @see KeyListener#keyPressed(KeyEvent)
	 */
	public void onKeyPressed(KeyEvent e)
	{
		currentScreens.peek().onKeyPressed(e);
	}

	/**
	 * @param e		an AWT {@link KeyEvent} representing the input event.
	 * @see KeyListener#keyReleased(KeyEvent)
	 */
	public void onKeyReleased(KeyEvent e)
	{
		currentScreens.peek().onKeyReleased(e);
		
	}

	/**
	 * @param e		an AWT {@link MouseEvent} representing the input event.
	 * @see MouseListener#mouseClicked(MouseEvent)
	 */
	public void onMouseClicked(MouseEvent e)
	{
		currentScreens.peek().onMouseClicked(e);
	}

	/**
	 * @param e		an AWT {@link MouseEvent} representing the input event.
	 * @see MouseListener#mousePressed(MouseEvent)
	 */
	public void onMousePressed(MouseEvent e)
	{
		currentScreens.peek().onMousePressed(e);
	}

	/**
	 * @param e		an AWT {@link MouseEvent} representing the input event.
	 * @see MouseListener#mouseReleased(MouseEvent)
	 */
	public void onMouseReleased(MouseEvent e)
	{
		currentScreens.peek().onMouseReleased(e);
	}

	/**
	 * @param e		an AWT {@link MouseEvent} representing the input event.
	 * @see MouseMotionListener#mouseDragged(MouseEvent)
	 */
	public void onMouseDragged(MouseEvent e)
	{
		currentScreens.peek().onMouseDragged(e);
	}

	/**
	 * @param e		an AWT {@link MouseEvent} representing the input event.
	 * @see MouseMotionListener#mouseMoved(MouseEvent)
	 */
	public void onMouseMoved(MouseEvent e)
	{
		currentScreens.peek().onMouseMoved(e);
	}
	

	/**
	 * @param e		an AWT {@link MouseWheelEvent} representing the input event.
	 * @see MouseWheelListener#mouseWheelMoved(MouseWheelEvent)
	 */
	public void onMouseWheelMoved(MouseWheelEvent e)
	{
		currentScreens.peek().onMouseWheelMoved(e);
	}

	/**
	 * Called when the size of the drawing area changes. Any subsequent calls to onDraw should note
	 * the new size and be sure to fill the entire area appropriately. Guaranteed to be called
	 * before the first call to onDraw.
	 * 
	 * @param newSize	the new size of the drawing area.
	 */
	public void onResize(Vec2i newSize)
	{
		size = newSize;
		for(Screen s: currentScreens)
		{
			s.onResize(newSize);	
		}
	}


}
